from django.contrib.auth.backends import ModelBackend
from md_shop_pro.settings import WEIBO_APP_KEY,WEIBO_APP_SECRET,WEIBO_FUNC_BACK,SECRET_KEY
from rest_framework_jwt.settings  import api_settings
import json
from urllib.parse import urlencode
from django.shortcuts import render
from django.views import View
# Create your views here.
from md_shop_pro.settings import STATICFILES_DIRS, DEFAULT_FROM_EMAIL, MEMCACHE_HOST, MEMCACHE_PORT
import io
from django.http import HttpResponse,JsonResponse
from PIL import Image,ImageDraw,ImageFont
from django.core.mail import send_mail
import random
import os,re
from django.core.cache import cache
from mdapp.models import *
from django.conf import settings
import memcache
from rest_framework.views import APIView
from . import serializer
from rest_framework.response import Response
import requests
from django.contrib.auth.hashers import check_password
def generate_code_image(image_uuid_code):
    '''
        验证码图片生成接口
            1. 生成图片
            2. 图片打上去随机字符串
            3. 随机字符串保存至memcached
            4. 返回图片
    '''
    bgcolor = (random.randrange(20, 100), random.randrange(
        20, 100), random.randrange(20, 100))
    width = 110
    height = 40
    # 创建画面对象
    im = Image.new('RGB', (width, height), bgcolor)
    # 创建画笔对象
    draw = ImageDraw.Draw(im)
    # 调用画笔的point()函数绘制噪点
    for i in range(0, 100):
        xy = (random.randrange(0, width), random.randrange(0, height))
        fill = (random.randrange(0, 255), 255, random.randrange(0, 255))
        draw.point(xy, fill=fill)
    # 定义验证码的备选值
    str = '1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm'
    # 随机选取4个值作为验证码
    rand_str = ''
    for i in range(0, 4):
        rand_str += str[random.randrange(0, len(str))]
    # 构造字体对象

    fonts_files = os.path.join(
        STATICFILES_DIRS[0], 'fonts/' + 'SourceCodePro-Medium.ttf')
    font = ImageFont.truetype(fonts_files, 30)
    # 构造字体颜色
    fontcolor1 = (255, random.randrange(0, 255), random.randrange(0, 255))
    fontcolor2 = (255, random.randrange(0, 255), random.randrange(0, 255))
    fontcolor3 = (255, random.randrange(0, 255), random.randrange(0, 255))
    fontcolor4 = (255, random.randrange(0, 255), random.randrange(0, 255))
    # 绘制4个字
    draw.text((5, 2), rand_str[0], font=font, fill=fontcolor1)
    draw.text((25, 2), rand_str[1], font=font, fill=fontcolor2)
    draw.text((50, 2), rand_str[2], font=font, fill=fontcolor3)
    draw.text((75, 2), rand_str[3], font=font, fill=fontcolor4)
    # 释放画笔
    del draw
    # 存入缓存，用于做进一步验证，并设置超时时间为10分组
    cache.set(image_uuid_code,rand_str.lower(),60*10) # 图片随机字符
    
    buf = io.BytesIO()
    # 将图片保存在内存中，文件类型为png
    im.save(buf, 'png')
    # 将内存中的图片数据返回给客户端，MIME类型为图片png！
    return HttpResponse(buf.getvalue(), 'image/png')

class ImageCode(View):
    def get(self,request,image_uuid_code):
        '''
            返回图片数据
            key: image_uuid_code
            value: random_str
        '''
        print("获取验证码")
        return generate_code_image(image_uuid_code)
    def post(self,request,image_uuid_code):
        '''
            校验图片验证码
        '''
        data = {}
        image_code = request.POST.get('image_code')
        cache_image_code = cache.get(image_uuid_code)
        print(image_code,'image_code')
        print(cache_image_code,'cache_image_code')
        if image_code == cache_image_code:
            data['code'] = 200
        else:
            data['code'] = 201
        return JsonResponse(data)
        # application/json;charset=UTF-8 | request Payload
        # application/x-www-form-urlencoded from-data
        # return HttpResponse('成功了')
        #res['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8080'

#注册用户名判断
class Is_user(View):
    def get(self,request):
        return HttpResponse('ok')
    def post(self,request):
        data={}
        name = request.POST.get('username')
        print(name)
        name = Users.objects.filter(username=name)
        if not name:
            data['code'] =200
        else:
            data['code']=201
        return JsonResponse(data)


#注册密码判断
class Is_password(View):
    def get(self,request):
        return HttpResponse('password')
    def post(self,request):
        data={}
        password = request.POST.get('password')
        print(password)
        pwd = re.match(r'^[1-9]\d{7,20}$',password)
        pwd1 = re.match(r'^^[A-Za-z]{7,20}$',password)
        pwd2 = re.match(r'^[a-zA-Z0-9][a-zA-Z0-9]{7,20}$',password)
        pwd3 = re.match(r'[\s\S]{7,20}$',password)
        if pwd:
            data['code'] =200
        elif pwd1:
            data['code']=200
        elif pwd2:
            data['code']=201
        elif pwd3:
            data['code']=202
        else:
            data['code']=200
        return JsonResponse(data)                          

#确认密码验证
class Is_pwd(View):
    def get(self,request):
        return HttpResponse('ispwd')
    def post(self,request):
        data={}
        password = request.POST.get('password')
        pwd = request.POST.get('pwd')
        print(password)
        if password == pwd:
            data['code'] =200
        else:
            data['code']=201
        return JsonResponse(data)

#手机号验证
class Is_phone(View):
    def get(self,request):
        return HttpResponse('ispwd')
    def post(self,request):
        data={}
        phone = request.POST.get('phone')
        print(phone)
        phone1 = re.match(r'^1[3-8]\d{9}$',phone)
        if phone1:
            data['code'] =200
        else:
            data['code']=201
        return JsonResponse(data)






class CacheCode:
    # 连接缓存数据库，加入值 获取值
    def __init__(self,host,port=11211):
        self.mc = memcache.Client([host],port)

    # 获取对应keyde value
    def get(self,key):
        return self.mc.get(key)

    def set(self,key,new_value,expire=60):
        self.mc.set(key,new_value,expire)

    def replace(self,key,new_value,expire=60):
        if not self.mc.replace(key,new_value,expire):
            self.set(key,new_value,expire)
        return True
    
class Email(View):
    def post(self,request):
        email = request.POST.get('email')
        print('*******')
        print(email)
        data={}

        # 发送激活邮件，包含激活链接: http://127.0.0.1:8000/user/active/3
        # 激活链接中需要包含用户的身份信息, 并且要把身份信息进行加密
        # serializer = Serializer(settings.SECRET_KEY,3600)
        # info={'confirm':1}
        # token = serializer.dumps(info)
        # token = token.decode()

        # 发送邮件
        str_ = '%06d'%(random.randint(0,999999))
        print(str_)
        # 存入缓存
        cache = CacheCode(settings.MEMCACHE_HOST,settings.MEMCACHE_PORT)
        cache.replace(email,str_)
        mes = '邮箱验证码为：{}'.format(str_)

        # 发送邮件
        send_mail('欢迎注册美多','',settings.EMAIL_HOST_USER,[email],html_message=mes)
        return JsonResponse(data)

# 校验邮箱验证码
class CheckEmail(View):
    def post(self,request):
        data={}
        email = request.POST.get('email')
        print(email)
        email_code = request.POST.get('email_code')
        cache = CacheCode(settings.MEMCACHE_HOST,settings.MEMCACHE_PORT)
        cache_str = cache.get(email)
        if cache_str == email_code:
            data['code']=200
        else:
            data['code']=201
        return JsonResponse(data)


#定义一个勾选
class Allow(View):
    def post(self,request):
        print('-----------------++++')
        data = {}
        allow = request.POST.get('allow')
        print(allow)
        if allow == 'true':
            data['code'] = 200
        else:
            data['code'] = 201
        return JsonResponse(data)

'''
    序列化： 将数据打包成json给到浏览器 -> vue -> 渲染到模板变量上
        json.dumps({'name':1})
        serializer 自带模块 -> 一些数据库中的特殊字段 比如时间 无法处理
        date、datetime、time、年月日-时分秒-微妙 -> '2018-09-08 8:5:12 30' '2018-09-08'
        drf: django-rest-framework -> serializer -> 正二八经可以来进行序列化操作的 
    反序列化： 前端POST提交 -> json -> 后端解析json -> 存储到数据库
        django-rest-framework
    pip install djangorestframework

    View的视图: django request->response 
        request.POST.get() 
    APIView: drf request.data

    序列化器：接受处理字段，抛出异常，自动入库
        接收一个参数，这个参数就是post提交上来的数据
    username 
    password
    password2
    email
    mobile
'''

# 1商品模块
    # 存储一个商品 序列化
# 2订单模块
    # 创建一个订单 反序列化
# 3地址模块
# 4评论模块
# 5个人模块

class Register(APIView):
    def post(self,request):
        '''
            POST 
            url：api/register/
        '''
        user = serializer.UserSerializer(data=request.data)
        # request.POST
        data = {}
        if user.is_valid(): # 数据要保存之前 先经过整体的验证 字段的验证
            
            user.save()# 保存数据 通过验证 最终调用create函数进行保存
            data['code'] = 200

            res = Response(data) # user这个序列化器中的data属性
            print(res)
            return res
        else:
            data['code'] = 201
            return Response(data)

def jwt_response_payload_handler(token, user=None, request=None, **kwargs):
    return {
        'token':token,
        'username': user.username,
        'user_id': user.id,
    }

from django.contrib.auth.backends import ModelBackend

class UserModelBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        '''
            多账号登陆
            username == account
            username == email 
            username == mobile
        '''
        try:
            user = Users.objects.get(username=username)
            # 校验 用户名是否是原来用户名
        except:
            user = None
            # 当前输入的不是用户名，可能是手机号 还有邮箱
            try:
                user = Users.objects.get(email=username)
            except:
                user = None
                user = Users.objects.get(mobile=username)
        if user and user.check_password(password):
            # a1234567 = pbkdf2_sha256$100000$ePk0zrf52uPG$jHKbpBaXhYVWipItYnv1vxFCMROuu1ccOP9xaB9oI7w=
            return user
#from django.contrib.auth import authenticate
#admin界面的用户管理系统才可以使用这个函数


# from rest_framework_jwt.settings import api_settings

# jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
# jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

# payload = jwt_payload_handler(user)
# token = jwt_encode_handler(payload)

# from rest_framework_jwt.utils import jwt_encode_handler

# WEIBO_APP_KEY = '3761383702'
# WEIBO_APP_SECRET = '28d3a16c173c976aec4f05309771fd93'

class Weibo_Url(APIView):


    def get(self,request):
        print('------')
        url = 'https://api.weibo.com/oauth2/authorize?' # 加问号走get不加问号走post 
        data = {
            'client_id': WEIBO_APP_KEY,
            'response_type': 'code',
            'redirect_uri': WEIBO_FUNC_BACK,
        }
        weibo_url = url + urlencode(data)
        # print(data)
        # print(weibo_url)
        return Response({'weibo_url':weibo_url})

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
# 创建payload的函数
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
# 创建token的函数

class Weibo_back(APIView):
    '''
        通过回调连接，获取access_token
        https://api.weibo.com/oauth2/access_token?
        client_id=YOUR_CLIENT_ID
        client_secret=YOUR_CLIENT_SECRET&
        grant_type=authorization_code&
        code=CODE
        redirect_uri=YOUR_REGISTERED_REDIRECT_URI
    '''

    def get(self, request):
        # print('==========')
        '''
            url: http://127.0.0.1:8000/weibo_back/
        '''
        code = request.query_params.get('code')
        # print(code)
        data = {
            'client_id': WEIBO_APP_KEY,
            'client_secret': WEIBO_APP_SECRET,
            'grant_type': 'authorization_code',
            'code': code,
            'redirect_uri': WEIBO_FUNC_BACK,
        }
        url = 'https://api.weibo.com/oauth2/access_token'
        response = json.loads(requests.post(
            url=url, data=data).text)  # 拿取请求的返回结果
        # {'access_token': '2.00jqYNTGfgNAXEbd85e6c672uTGF8E',
        # 'remind_in': '157679999', 'expires_in': 157679999,
        # 'uid': '5928542965', 'isRealName': 'true'}
        # print(re'sponse)
        uid = response.get('uid')
        print(uid,'------------------------------')
        if not uid:
            # 获取不到则为出错
            return Response({'code': 201, 'error': '三方授权失败'})
        # 判断当前UID是否存在与数据库中
            # 如果存在，代表用户可以登陆的
            # 如果不存在，代表这个用户不能登陆，先得去绑定数据
        try:
            user = SocialUser.objects.get(uid=uid)
            # user.user # 外键关联的用户
        except:
            return Response(
                {
                    'code': 201,
                    'response': json.dumps(response)
                }
            )
            '''
                不光要返回状态码201，还要返回response
                绑定接口 ，需要用到uid和access_token
                前端持有 response -> 另外绑定接口
                绑定接口是不是就可以 拿response['access_token'] ['uid']
                    获取用户的微博信息
            '''
        else:
            payload = jwt_payload_handler(user.user)  # 创建载荷
            token = jwt_encode_handler(payload)  # 创建token
            return Response({
                'code': 200,
                'token': token,
                'username': user.user.username,
                'user_id': user.user.id,
            })

        # request.data
        # request.paras


from django.db import transaction


class UserBind(APIView):
    def post(self,request):
        from django.http import QueryDict
        username = request.data['username']
        password = request.data['password']
        password2 = request.data['password2']
        try:
            access_token_object = json.loads(request.data.get('access_token'))
            print(access_token_object)
            # print(access_token_object)
        except:
            return Response({'code':201,'mes':'没有三方认证'})

        if not all([username,password,access_token_object]):
            mes = {'code':201,'mes':'输入不能为空'}
            return Response(mes)
        else:
            # 拼接访问微博获取用户基本信息链接
            get_user_url = "https://api.weibo.com/2/users/show.json?access_token=%s&uid=%s"%(
            access_token_object['access_token'],access_token_object['uid'])

            # 获取到了用户信息 准备入库
            # data = requests.get(url=get_user_url).text
            # print(data,'1111111111111111111111111')
            data_user = {'username':username,'password':password,'password2':password2,'email':'***@qq.com','mobile':'***'}
            # print(data_user['username'],'6666666666666')
            # 反序列化器只接收 QueryDict对象 这里转类型
            queryDict_user = QueryDict('',mutable=True)
            queryDict_user.update(data_user)
            # print(queryDict_user,'qqqqqqqqqq')
            try:
                with transaction.atomic():
                    # print('11111111111111111111111111')
                    user = serializer.UserSerializer(data=queryDict_user)
                    if user.is_valid():
                        user.save()
                    # print(user,'uuuuuuuuuuu')
                    users = Users.objects.filter(username=username).first()

                    print(users,'555555555555555555555555555555555555555555555555555')

                    data_socialuser = {'platfrom_ID':1,'platfrom_type':2,'uid':access_token_object['uid']}

                    queryDict_socialuser = QueryDict('', mutable=True)
                    queryDict_socialuser.update(data_socialuser)
                                                                                # 涉及到外键就要把对象传过去反序列器接受
                    socialuser = serializer.socialuserSerializer(data=queryDict_socialuser,context={'outer_key':users})
                
                    if socialuser.is_valid():
                        socialuser.save()
                        
                        payload = jwt_payload_handler(users)   # 创建载荷
                        token = jwt_encode_handler(payload)              # 创建 token
                        mes = {'token':token,'username':users.username,'user_id':users.id}
                        
                        return Response(mes)
                    else:
                        print(socialuser.errors)
                    return Response({'mes':'都没有入库'})
                    
            except Exception as a:
                print(a,"-------------------------------")
                return Response('授权失败')


# class UserBind(APIView):
#     def post(self,request):
#         '''
#             要绑定用户
#             首先创建一个用户数据
#             作为外键关联到社交表
#             user: 赋值的是一个外键，多对一，那么应该是一个用户对象'zhangsan'
#             platfrom_ID:1
#             platfrom_type:2
#             uid:access_token.get('uid)
#        '''


#         user = serializer.UserSerializer(
#             data = request.data # QueryDict-> 序列化器中 -> 反序列化入库

#         )
#             # 绑定表单 username password password2 email mobile
#         if user.is_valid():
#             # 校验数据
#             user = user.save()
#             # save -> create -> user_object
#             # user.errors
#         else:
#             return Response(
#                 user.errors
#             )

#         socialuser_data = {
#             'user':user, # 报错  外键赋值的是一个数据，其实是数据的id
#             'platfrom_ID':1,
#             'platfrom_type':2,
#             'uid':access_token.get('uid')
#         }
#         # 手动构建序列化器的外键数据传入

#         socialuser = serializer.SocialUserSerialzer(
#             data = socialuser_data
#         )

#         if socialuser.is_valid():
#             socialuser.save()
        
#         else:
#             return Response(
#                 socialuser.errors
#             )
#         return Response(
#             {'code':200}
#         )


from rest_framework import generics
# generics.RetrieveAPIView
from rest_framework.permissions import IsAuthenticated

'''
    登陆用户可以看到个人信息
        校验jwt
        返回个人信息
    RBAC
'''

# 查看个人用户信息
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
class User_center_info(APIView):
    permission_classes = (IsAuthenticated,)
    # IsAuthenticated验证结束，如果验证OK 有效用户对象会被保存
    # request.user
    def get(self,request):
        user = request.user
        user_info = serializer.UserSerializer(
            instance = user
        )
        return Response(
            user_info.data
        )

class Xiuuserpassword(APIView):
    '''
        密码修改功能
        old_password: 
            首先要比对当前用户输入的旧密码是否和数据库的一样
        new_password: 如果一样，新密码覆盖旧密码
    '''
    permission_classes = (IsAuthenticated,)

    def post(self,request):
        user = request.user
        xiu_user = serializer.ChangeUserPasswordSerializer(
            instance = user, # OBEJCT
            data = request.data # JSON
        )
        # data: create
        # instance,data:update
        if xiu_user.is_valid():
            xiu_user.save()
            return Response({
                'code':200,
            })
        else:
            return Response({
                'code':201
            })

'''
    celery发送邮件
    找回密码
    JSONWebSignatureSerializer 序列化对象，生成token的
    SignatureExpired 当解密token，如果token过期，抛出SignatureExpired异常
'''
# # JSONWebSignatureSerializer()
from itsdangerous import TimedJSONWebSignatureSerializer,SignatureExpired
from . import tasks
ser = TimedJSONWebSignatureSerializer(SECRET_KEY,6000)

class SendEmail(APIView):
    '''
        接收email，发送token回调连接
    '''
    def post(self,request):
        data = {
            'email':request.data['email']
        } 

        token = ser.dumps(data).decode()
 

        tasks.send_reset_email.delay(request.data['email'],token)
        return Response(
            {'code':200},
        )

class ResetPass(APIView):
    def post(self,request):
        token = request.data['token']
        password = request.data['password']
        print(password,'1111111')
        print(ser.loads(token))
        try:
            email = ser.loads(token)['email']
            print(email,'22222222222')
        except SignatureExpired:
            return Response(
                {'data':'邮箱过期'},
            )
        user = Users.objects.get(email=email)
        print(user,'3333333')
        # user就是待修用户
        reset_user = serializer.ResetpassSerializer(
            instance = user,
            data = {
                'password':password,
            }
        )
        if reset_user.is_valid():
            reset_user.save()
            return Response(
                {'code':200}
            )
        else:
            return Response(
                {'code':201}
            )
'''
    请求省市区的数据称为接口
    页面静态化
'''
from rest_framework import generics
class Provinceiew(generics.ListAPIView):
    '''
        GET
    '''
    #is_delete
    queryset = Areas.objects.filter(parent=None)   # 省数据不关联任何数据
    serializer_class = serializer.AreaSerialzer

class ProvinceSubsView(generics.ListAPIView):
    '''
        GET
        ? 
        /id/
    '''
    serializer_class = serializer.AreaSerialzer

    def get_queryset(self):
        # print('------------')
        # print(self.kwargs)
        id = self.kwargs['id']
        # print(parent)
        #self.user -> user
        #self.kwargs -> 连接参数 
        # {'area_id': 110000}
        # print(models.Areas.objects.filter(
        #     parent__area_id = parent,
        # ))
        return Areas.objects.filter(
            parent__id = id,
        )

# 地址入库
class Inert_addres(APIView):

    permission_classes = (IsAuthenticated,)

    def post(self,request):

        user = request.user
        province_id = request.data['province']
        city_id = request.data['city']
        town_id = request.data['town']
        adres_id = request.data['adres_id']    # 获取前端传的ID，有ID就是修改，没有就是添加

        if not all([province_id,city_id,town_id]):
            return Response({'code':201,'mes':'选项不能为空'})

        province = Areas.objects.filter(id=province_id).first()

        city = Areas.objects.filter(id=city_id).first()
        town = Areas.objects.filter(id=town_id).first()
        
        # 有 id 就是修改 这一块是涉及后面的编辑地址的
        # 点击编辑也是打开的地址框，但编辑时地址框是应该有数据的，所以这里用前端是否有传ID判断		    是添加还是编辑
        if adres_id:
            receiver = request.data['receiver']
            place = request.data['place']
            mobile = request.data['mobile']
            email = request.data['email']
            Address.objects.filter(id=adres_id).update(
                receiver = receiver,place = place,mobile = mobile,email = email,
                province = province,city = city,town = town
            )
            return Response({'code':200})
        else:
        	# 将 数据对象传参到序列化器
            address = serializer.addressSerializer(data=request.data,context={'user':user,'province':province,'city':city,'town':town})
            if address.is_valid():
                address.save()
                return Response({'code':200})
            else:

                return Response({'code':201,'mes':address.errors})


# 获取用户地址
class Get_address(APIView):
    permission_classes = (IsAuthenticated,)
    
    def get(self,request):
        user = request.user
        print('11111111111111')
        address = Address.objects.filter(user=user,is_delete=False,default_address=0).all()

        address_all = Address.objects.filter(user=user,is_delete=False).all()
        len_address = len(address_all)
        user_address = serializer.addressSerializer(instance=address,many=True)

        return Response({
            'address':user_address.data,
            'len_address':len_address
        })

# 获取默认地址
class Def_address(APIView):

    permission_classes = (IsAuthenticated,)

    def get(self,request):
        user = request.user
        print('22222222222222')
        address = Address.objects.filter(user=user,is_delete=False,default_address=1).all()

        if address:
            def_address = serializer.addressSerializer(instance=address,many=True)

            return Response(
                {'code':200,'mes':def_address.data}
            )
        else:
            return Response(
                {'code':201}
            )



from django.db.models import Q   # ~Q：不等于  
# 设置默认地址
class Set_def_address(APIView):

    # pid :正则路由传参
    def get(self,request,pid):
        print('-----------1111')
    # 将当前ID的地址设为默认
        Address.objects.filter(id=pid).update(default_address=1)
        # 将别的地址设为 不默认
        Address.objects.filter(~Q(id=pid)).update(default_address=0)

        return Response({'code':200})

# 删除地址
class Shanchu(APIView):
    permission_classes = (IsAuthenticated,)

    def get(self,request,cid):
 
        Address.objects.filter(id=cid).update(is_delete=True)

        return Response({'code':200})


# 修改地址
class Redact_address(APIView):

    permission_classes = (IsAuthenticated,)

    def get(self,request,adres_id):

            address = Address.objects.filter(id=adres_id).first()
            print(address)
            if address:
                red_address = serializer.addressSerializer(instance=address)

                return Response({'code':200,'mes':red_address.data})

            else:
                return Response({'code':201})
